/*
 * Copyright (c) 2016. For Intelligent Group.
 */

package com.intelligent.mts.da.handler;


import com.intelligent.mts.common.utils.Identities;
import com.intelligent.mts.core.dto.HistoryDto;
import com.intelligent.mts.core.dto.SerialNumberDto;
import com.intelligent.mts.core.dto.TrackDto;
import com.intelligent.mts.core.service.DataSearchService;
import com.intelligent.mts.core.utils.AppConst;
import com.intelligent.mts.da.message.ProcessMessage;
import com.intelligent.mts.da.message.ReceiveMessage;
import com.intelligent.mts.da.utils.ApplicationBeanUtils;
import com.intelligent.mts.da.utils.MessageUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;

/**
 * Created by Julia.Zhou on 2016/07/20.
 */
public class UpdateStatusHandler extends ChannelInboundHandlerAdapter {

    public static Logger logger = LoggerFactory.getLogger(UpdateStatusHandler.class);
    private DataSearchService dataSearchService;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String returnMessage = "";
        String productionId = null;
        String productionId1 = null;
        String HsproductionId = null;
        String testProductionId = null;
        ReceiveMessage receiveMessage = (ReceiveMessage) msg;
        String station = receiveMessage.getStationId();
        try {
            logger.info("Start write data process.");
            this.setService();
            AttributeKey<ReceiveMessage> attributeKey = AttributeKey.valueOf(AppConst.VALIDATE_DATA);
            ReceiveMessage preReceiveMessages = ctx.channel().attr(attributeKey).get();
            if (preReceiveMessages == null) {
                logger.error("Link maybe disconnect, please restart 1010 process");
                return;
            } else {
                Boolean result = MessageUtils.isValidate(receiveMessage, preReceiveMessages);
                if(StringUtils.isNotBlank(preReceiveMessages.getResult()) && preReceiveMessages.getResult().equals(AppConst.RESULT_NG)){
                    result = false;
                }
                if (!result) {
                    returnMessage = AppConst.START_STATUS_RESP + AppConst.SEPARATOR + station + AppConst.SEPARATOR + AppConst.RESULT_NG + AppConst.END_FLAG;
                } else {
                    if (AppConst.STATION_0620.equals(receiveMessage.getStationId())){
                        if (!receiveMessage.getResult().equals(AppConst.RESULT_NG)) {
                            productionId = dataSearchService.findProductionIdBySerialValue(preReceiveMessages.getPcba());
                            HsproductionId = dataSearchService.findHsProductionId(productionId);
                            if (StringUtils.isNotBlank(productionId)) {
                                boolean isExist = false;
                                SerialNumberDto serialNumberDto = dataSearchService.findCondition(productionId, preReceiveMessages.getStationId(), AppConst.SN_HS);
                                if (serialNumberDto == null){
                                    String productionId2 = dataSearchService.findProductionIdBySerialValue(preReceiveMessages.getHs());
                                    if (StringUtils.isNotBlank(productionId2)) {
                                        isExist = true;
                                    }
                                } else {
                                    isExist = true;
                                }

                                if (!isExist){
                                    serialNumberDto = new SerialNumberDto();
                                    serialNumberDto.setProductionId(HsproductionId);
                                    serialNumberDto.setStationId(receiveMessage.getStationId());
                                    serialNumberDto.setSerialName(AppConst.SN_HS);
                                    serialNumberDto.setSerialValue(preReceiveMessages.getHs());
                                    serialNumberDto.setPnValue(preReceiveMessages.getHsPn());
                                    dataSearchService.createSerialNumber(serialNumberDto);
                                } else {
                                    serialNumberDto = new SerialNumberDto();
                                    serialNumberDto.setProductionId(HsproductionId);
                                    serialNumberDto.setStationId(receiveMessage.getStationId());
                                    serialNumberDto.setSerialName(AppConst.SN_HS);
                                    serialNumberDto.setSerialValue(preReceiveMessages.getHs());
                                    serialNumberDto.setPnValue(preReceiveMessages.getHsPn());
                                    dataSearchService.updateProductionId(serialNumberDto);
                                }
                                preReceiveMessages.setProductionId(productionId);
                            }
                        }
                    }

                    if (AppConst.STATION_0930.equals(receiveMessage.getStationId())){
                        if (!receiveMessage.getResult().equals(AppConst.RESULT_NG)) {
                            String parentId = Identities.randomBase62(8);
                            productionId = dataSearchService.findProductionIdBySerialValue(preReceiveMessages.getHs());
                            productionId1 = dataSearchService.findProductionIdBySerialValue(preReceiveMessages.getHou());
                            parentId = dataSearchService.updateProduction(productionId, productionId1, parentId);
                            if (StringUtils.isNotBlank(parentId)){
                                preReceiveMessages.setProductionId(parentId);
                            } else {
                                logger.error("two more production exits ParentproductionId");
                                returnMessage = AppConst.START_STATUS_RESP + AppConst.SEPARATOR + station + AppConst.SEPARATOR + AppConst.RESULT_NG + AppConst.END_FLAG;
                                ctx.writeAndFlush(returnMessage);
                            }
                        }
                    }
                    for (String sn : receiveMessage.getSnLists().values()) {
                        testProductionId = dataSearchService.findProductionIdBySerialValue(sn);
                    }
                    if (testProductionId.equals(AppConst.PRODUCTION_ID_0650) || testProductionId.equals(AppConst.PRODUCTION_ID_0690) ||
                            testProductionId.equals(AppConst.PRODUCTION_ID_0750) || testProductionId.equals(AppConst.PRODUCTION_ID_0990) ||
                            testProductionId.equals(AppConst.PRODUCTION_ID_1020) || testProductionId.equals(AppConst.PRODUCTION_ID_1030) ||
                            testProductionId.equals(AppConst.PRODUCTION_ID_1050) || testProductionId.equals(AppConst.PRODUCTION_ID_1060)){
                        returnMessage = AppConst.START_STATUS_RESP + AppConst.SEPARATOR + station + AppConst.SEPARATOR + AppConst.RESULT_OK + AppConst.END_FLAG;
                        saveHistory(receiveMessage, preReceiveMessages);
                        ctx.fireChannelRead(returnMessage);
                        return;
                    }

                    String resultMessage = this.saveOrUpdateTrack(receiveMessage, preReceiveMessages);
                    returnMessage = AppConst.START_STATUS_RESP + AppConst.SEPARATOR + station + AppConst.SEPARATOR + resultMessage + AppConst.END_FLAG;
                    saveHistory(receiveMessage, preReceiveMessages);
                    ctx.channel().attr(attributeKey).set(null);
                }
            }
//            ctx.writeAndFlush(returnMessage);
            ctx.fireChannelRead(returnMessage);
            logger.info("Process finish, return:[{}]", returnMessage);
        } catch (Exception e) {
            returnMessage = AppConst.START_STATUS_RESP + AppConst.SEPARATOR + station + AppConst.SEPARATOR + AppConst.RESULT_NG + AppConst.END_FLAG;
            ctx.writeAndFlush(returnMessage);
            logger.info("Process finish, return:[{}]", returnMessage);
            logger.error("Exception found:[{}]", e.getMessage());
            e.printStackTrace();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.warn("Unexpected exception from com.intelligent.mts.da.handler " + cause);
        ctx.fireExceptionCaught(cause);
    }

    private void saveHistory(ReceiveMessage receiveMessage, ReceiveMessage preReceiveMessage) {
        logger.info("Create history information, productionId:[{}]", preReceiveMessage.getProductionId());
        String stationId = receiveMessage.getStationId();

        String pcba = receiveMessage.getPcba();
        String hou = receiveMessage.getHou();
        String hs = receiveMessage.getHs();
        String tht = receiveMessage.getDsp_s();
        String dsp = receiveMessage.getDsp_p();
        String gw = receiveMessage.getGw();

        HistoryDto historyDto = new HistoryDto();
        historyDto.setProductionId(preReceiveMessage.getProductionId());
        historyDto.setStationId(stationId);

        List<ProcessMessage> processMessageList = MessageUtils.getProcessMessage();
        if (processMessageList != null && !processMessageList.isEmpty()) {
            for (ProcessMessage processMessage : processMessageList) {
                if (stationId.equals(processMessage.getSid())) {
                    historyDto.setStationName(processMessage.getSname());
                    break;
                }
            }
        }
        List<ProcessMessage> processSuMessageList = MessageUtils.getProcessSuMessage();
        if (processSuMessageList != null && !processSuMessageList.isEmpty()) {
            for (ProcessMessage processMessage : processSuMessageList) {
                if (stationId.equals(processMessage.getSid())) {
                    historyDto.setStationName(processMessage.getSname());
                    break;
                }
            }
        }
        historyDto.setCreateTime(new Date());
        String result = receiveMessage.getResult();
        if (StringUtils.isNotBlank(pcba) || StringUtils.isNotBlank(preReceiveMessage.getPcba())) {
            historyDto.setPcba(result);
        }

        if (StringUtils.isNotBlank(hou) || StringUtils.isNotBlank(preReceiveMessage.getHou())) {
            historyDto.setHou(result);
        }

        if (StringUtils.isNotBlank(hs) || StringUtils.isNotBlank(preReceiveMessage.getHs())) {
            historyDto.setHs(result);
        }

        if (StringUtils.isNotBlank(tht) || StringUtils.isNotBlank(preReceiveMessage.getDsp_s())) {
            historyDto.setTht(result);
        }

        if (StringUtils.isNotBlank(dsp) || StringUtils.isNotBlank(preReceiveMessage.getDsp_p())) {
            historyDto.setDsp(result);
        }

        if (StringUtils.isNotBlank(gw) || StringUtils.isNotBlank(preReceiveMessage.getGw())) {
            historyDto.setGw(result);
        }
        if (AppConst.RESULT_NG.equals(historyDto.getPcba()) || AppConst.RESULT_NG.equals(historyDto.getHou())
                || AppConst.RESULT_NG.equals(historyDto.getHs()) || AppConst.RESULT_NG.equals(historyDto.getTht())
                || AppConst.RESULT_NG.equals(historyDto.getDsp()) || AppConst.RESULT_NG.equals(historyDto.getGw())) {

            historyDto.setResult(AppConst.RESULT_NG);
        } else {
            if (StringUtils.isBlank(historyDto.getPcba()) && StringUtils.isBlank(historyDto.getHou())
                    && StringUtils.isBlank(historyDto.getHs()) && StringUtils.isBlank(historyDto.getTht())
                    && StringUtils.isBlank(historyDto.getDsp()) && StringUtils.isBlank(historyDto.getGw())) {
                historyDto.setResult(AppConst.RESULT_NG);
            } else{
                historyDto.setResult(AppConst.RESULT_OK);
            }
        }
        dataSearchService.createHistory(historyDto);
        logger.info("Create history finish, result:[{}]", historyDto.getResult());
    }

    private String saveOrUpdateTrack(ReceiveMessage receiveMessage, ReceiveMessage preReceiveMessage) {
        logger.info("Update tracking status, result:[{}]", receiveMessage.getResult());
        String result = null;
        String stationId = receiveMessage.getStationId();
        String lineId = receiveMessage.getLineId();

        String productionId = null;
        if (receiveMessage.getSnLists() != null && !receiveMessage.getSnLists().isEmpty()) {
            for (String snName : receiveMessage.getSnLists().keySet()) {
                if (StringUtils.isNotBlank(receiveMessage.getSnLists().get(snName))) {
                    productionId = dataSearchService.findProductionIdBySerialValue(receiveMessage.getSnLists().get(snName));
                    if (StringUtils.isNotBlank(productionId)) {
                        break;
                    }
                }
            }
        }
        if (StringUtils.isBlank(productionId)) {
            logger.info("Process sequence is incorrect.");
            return AppConst.RESULT_NG;
        }

        TrackDto trackDto = dataSearchService.findTrackByProductionId(productionId);
        if (trackDto != null) {
            trackDto.setStationId(stationId);
            this.setTrackStatus(trackDto, receiveMessage, preReceiveMessage);
            dataSearchService.update(trackDto);
            logger.info("Update tracking status finish, status:[{}]", trackDto.getStatus());

        } else {
            TrackDto trackDto1 = new TrackDto();
            trackDto1.setLineId(lineId);
            trackDto1.setProductionId(productionId);
            trackDto1.setStationId(stationId);
            this.setTrackStatus(trackDto1, receiveMessage, preReceiveMessage);
            dataSearchService.createTrack(trackDto1);
            logger.info("Update tracking status finish, status:[{}]", trackDto1.getStatus());
        }
        result = AppConst.RESULT_OK;
        logger.info("Update tracking status finish.");
        return result;
    }

    private void setTrackStatus(TrackDto trackDto, ReceiveMessage receiveMessage, ReceiveMessage preReceiveMessage) {
        String pcba = receiveMessage.getPcba();
        String hou = receiveMessage.getHou();
        String hs = receiveMessage.getHs();
        String tht = receiveMessage.getDsp_s();
        String dsp = receiveMessage.getDsp_p();
        String gw = receiveMessage.getGw();
        String result = receiveMessage.getResult();
        if (StringUtils.isNotBlank(pcba) || StringUtils.isNotBlank(preReceiveMessage.getPcba())) {
            trackDto.setPcba(result);
        }

        if (StringUtils.isNotBlank(hou) || StringUtils.isNotBlank(preReceiveMessage.getHou())) {
            trackDto.setHou(result);
        }

        if (StringUtils.isNotBlank(hs) || StringUtils.isNotBlank(preReceiveMessage.getHs())) {
            trackDto.setHs(result);
        }

        if (StringUtils.isNotBlank(tht) || StringUtils.isNotBlank(preReceiveMessage.getDsp_s())) {
            trackDto.setDsp_s(result);
        }

        if (StringUtils.isNotBlank(dsp) || StringUtils.isNotBlank(preReceiveMessage.getDsp_p())) {
            trackDto.setDsp_p(result);
        }

        if (StringUtils.isNotBlank(gw) || StringUtils.isNotBlank(preReceiveMessage.getGw())) {
            trackDto.setGw(result);
        }
        if (AppConst.RESULT_NG.equals(trackDto.getPcba()) || AppConst.RESULT_NG.equals(trackDto.getHou())
                || AppConst.RESULT_NG.equals(trackDto.getHs()) || AppConst.RESULT_NG.equals(trackDto.getDsp_s())
                || AppConst.RESULT_NG.equals(trackDto.getDsp_p()) || AppConst.RESULT_NG.equals(trackDto.getGw())) {

            trackDto.setStatus(AppConst.RESULT_NG);
        } else {
            if (StringUtils.isBlank(trackDto.getPcba()) && StringUtils.isBlank(trackDto.getHou())
                    && StringUtils.isBlank(trackDto.getHs()) && StringUtils.isBlank(trackDto.getDsp_s())
                    && StringUtils.isBlank(trackDto.getDsp_p()) && StringUtils.isBlank(trackDto.getGw())) {
                trackDto.setStatus(AppConst.RESULT_NG);
            } else{
                trackDto.setStatus(AppConst.RESULT_OK);
            }
        }

        List<ProcessMessage> processMessageList = MessageUtils.getProcessMessage();
        if (processMessageList != null && !processMessageList.isEmpty()) {
            boolean next = false;
            if (receiveMessage.getStationId().equals(processMessageList.get(processMessageList.size() - 1).getSid())) {
                trackDto.setNextStation("-");
            } else {
                for (ProcessMessage processMessage : processMessageList) {
                    if (receiveMessage.getStationId().equals(processMessage.getSid())) {
                        next = true;
                        continue;
                    }

                    if (next) {
                        trackDto.setNextStation(processMessage.getSid());
                        break;
                    }
                }
            }
        }

        List<ProcessMessage> processSuMessageList = MessageUtils.getProcessSuMessage();
        if (processSuMessageList != null && !processSuMessageList.isEmpty()) {
            boolean next = false;
            for (ProcessMessage processMessage : processSuMessageList) {
                if (receiveMessage.getStationId().equals(processMessage.getSid())) {
                    next = true;
                    continue;
                }
                if (next) {
                    trackDto.setNextStation(processMessage.getSid());
                    break;
                }
            }
        }
    }

    public void setService() {
        if (dataSearchService == null) {
            dataSearchService = ApplicationBeanUtils.getBean(DataSearchService.class);
        }
    }
}
